<?php

/*
 * This collection of functions (libary) is licensed under GPL2.
 * See LICENSE or www.gnu.org for more details.
 *
 *  State handlers for Dataz state machine that is in dzManager.
 *  Separate file is used to keep the state machine more compact.
 *
 *  @author Hanri Ranki
 *
 *  $Id: dzstates.php 597 2006-04-03 16:15:46Z jyry $
 */

include_once("sogeneric.php");
include_once("sodebug.php");
include_once("dzconst.php");
include_once("dzsession.php");
include_once("dzviewstack.php");
include_once("dzsmconst.php");
include_once("dzevent.php");
include_once("dztemplate.php");
include_once("dzpurkki.php");
include_once("dzgeneric.php");
include_once("dzmenu.php");
include_once("dzerror.php");
include_once("dzlogin.php");
include_once("soconst.php");


/** Activates the view which number is in $SesData->viewPos
 *  @param dzSession $SesData Current session data
 *  @return int    The next state to move to
 */
function dzSMH_ActivateView(&$SesData) {
    soDebug("dzStates: dzSMH_ActivateView Id=".$SesData->ViewPos, SOD_DET);

	/* get the view number from the view title */
    $id = $SesData->ViewOrder->getItem($SesData->ViewPos);
    if ($SesData->changeToViewStack($id)) {
        $result = DZ_STATE_RECOVER_ERROR;
        soDebug("dzStates: View activate ok", SOD_DET);
    } else {
        $result = DZ_STATE_GO_INITIAL;
        soDebug("dzStates: Error activating the view", SOD_LO_ER);
    }

    return $result;
} // dzSMH_ActivateView


/** Commit the current new line in the group that caused the new line
 *  event and insert a new "new line"
 *  @param dzSession $SesData Current session data
 *  @return int    The next state to move to
 */
function dzSMH_AddLine(&$SesData) {
    soDebug("dzStates: dzSMH_AddLine", SOD_DET);
    $widget = &$SesData->HotView->Template->WidgetData;
    $grp = soExtractVal($widget->getItem(DZRI_WIDGET), "_", 2);
    soDebug("dzStates: Adding a new line to group $grp", SOD_DET);

    $SesData->HotView->Laituri->commitNew($grp);
    /* Set default values to the last row */
    $SesData->setDefaultValues($grp);

    /* Return the focus there where we left */
    $options = $widget->getItem(DZRI_OPTIONS);
    $SesData->HotView->Template->addInitAction(DZIA_SET_FOCUS, $options);

    return DZ_STATE_GO_EDIT_LOOP;
} // dzSMH_AddLine


/** Add a new view into the session
 *  @param dzSession $SesData Current session data
 *  @return int The next state to move to
 */
function dzSMH_AddView(&$SesData) {
    soDebug("dzStates: dzSMH_AddView", SOD_DET);

    /* Get the choosen menu action */
    $options = $SesData->HotView->Template->WidgetData->getItem(DZRI_OPTIONS);

    /* Parse the menu item action target and source stream */
    $action = dzParseMenuTarget($options);

#    $pre_call_def =
#        $SesData->HotView->Template->getFormOption(DZE_PRE_FORM.$mode);
#    if ($pre_call_def == NULL) {
#        $pre_call_def =
#            $SesData->HotView->Template->getFormOption(DZE_PRE_FORM);
#    }; // if

    /* Handle the pre-form event if it was defined */
#    if (soGetClass($pre_call_def) == "soset") {
#        handleSubariEventItem($pre_call_def, $SesData);
#    }; // if

    switch ($action->Target) {
        case DZMT_NALLE:
            $viewId = $SesData->addViewStack($action->Stream);
            if ($viewId >= 0) {
                if ($SesData->changeToViewStack($viewId)) {
                    if ($SesData->HotView->Template->isPseudo()) {
                        $result = DZ_STATE_START_NEW;
                    } else {
                        $result = DZ_STATE_START_QUERY;
                    }; // else if
                    soDebug("dzStates: Changed view to ".$viewId, SOD_LO);
                } else {
                    $result = DZ_STATE_GO_INITIAL;
                    soDebug("dzStates: error changing to the new view",
                             SOD_LO_E);
                }
            } else {
                $result = DZ_STATE_GO_INITIAL;
                soDebug("dzStates: Error creating the new view", SOD_LO_E);
            }
        break;

        case DZMT_EXT_WINDOW:
            $store_str = "";
            $split = soSplitStr($action->Stream, ",", 1);
            if (count($split)) {
                $action->Stream = $split[0];
                $store_name = soCaseConv($split[1], "U");
            } // if
            $type = $SesData->HotView->Template->getViewData(DZ_VI_TYPE);
            /* If a store encode it to url string */
            if ((count($split)) && ($type != DZ_VIEW_TYPE_DIALOG)) {
                $store = $SesData->HotView->Laituri->getStore($store_name);
                if (!soIsNull($store)) {
                    $store_str = "?".$store->encode();
                } // if
            } // if

            $SesData->HotView->Template->addInitAction(DZIA_OPEN_NEW_WINDOW,
                $action->Stream.$store_str);
            soDebug("dzStates: Added ini action to open a new browser ".
                    "window  with url: ".$action->Stream, SOD_LO_E);

            $result = DZ_STATE_RECOVER_ERROR;
        break;

    } // switch

    return $result;
} // dzSMH_AddView


/** Moves the browse pointer forward or backward.
 *  @param dzSession $SesData Current session data
 *  @param $Direction Indicates the direction to move.(1 = forward, -1 = backward)
 *  @return int The next state to move to
 */
function dzSMH_BrowseJump(&$SesData, $Direction) {
    soDebug("dzStates: dzSMH_BrowseJump", SOD_DET);
    $SesData->HotView->Laituri->jumpBrowsePos($Direction);

    return DZ_STATE_GO_BROWSE;
} // dzSMH_BrowseJump


/** Handle rollback after edit
 *  @param dzSession $SesData Refrence to the current session
 *  @return The next state to move to
 */
function dzSMH_CancelEdit(&$SesData) {
    soDebug("dzStates: dzSMH_CancelEdit", SOD_DET);

    /* Finish editing in Purkki. That is remove new lines from every group */
    $SesData->HotView->Laituri->finishEdit();
    $result = DZ_STATE_GO_BROWSE;

    $template = &$SesData->HotView->Template;
    $enter_state = $template->getViewData(DZ_VI_ENTER_STATE);
    /* If adding new find out the the following mode (query/browse)*/
    if ($enter_state == DZ_STATE_FROM_NEW_LOOP) {
        if ($template->isPseudo()) {
            return dzSMH_KillView($SesData);
        } else {
            $next_State =
                $template->getFormOption(DZFO_AFTER_NEW);
            if ($next_State == DZM_QUERY) $result = DZ_STATE_START_QUERY;
        } // else if
    } else {
        /* Release locks */
        $release_result = $SesData->HotView->Laituri->releaseLock();
        if ($release_result != NULL) {
            /* Some error occerred during the rpc. Insert message to
               message log.  */
            $SesData->ErrorLog->add($release_result);
        } // if
    } // if $enter_state

    return $result;
} // dzSMH_CancelEdit


/** Change the browse representation from list to form and vice versa
 *  @param dzSession $SesData Current session data
 *  @return int The next state to move to
 */
function dzSMH_ChangeBrowseMode(&$SesData) {
    soDebug("dzStates: dzSMH_ChangeBrowseMode", SOD_DET);
    $browse_mode = $SesData->HotView->Template->getViewData(DZ_VI_BROWSE_MODE);
    /* Change the browse mode. */
    $browse_mode = ($browse_mode == DZBM_LIST) ? DZBM_FORM : DZBM_LIST;
    $SesData->HotView->Template->setViewData(DZ_VI_BROWSE_MODE, $browse_mode);
    soDebug("dzStates: Browse changed to mode ".$browse_mode, SOD_DET);

    return DZ_STATE_GO_BROWSE;
} // dzSMH_ChangeOrder


/** Change the order of the rows
 *  @param dzSession $SesData Current session data
 *  @return int The next state to move to
 */
function dzSMH_ChangeOrder(&$SesData) {
    soDebug("dzStates: dzSMH_ChangeOrder", SOD_DET);

    return DZ_STATE_INIT_BROWSE;
} // dzSMH_ChangeOrder


/** Commit the changes user made.
 *  @param dzSession $SesData Refrence to the current session
 *  @return The next state to move to
 */
function dzSMH_CommitEdit(&$SesData) {
    soDebug("dzStates: dzSMH_CommitEdit", SOD_DET);
    $template = &$SesData->HotView->Template;
    $laituri = &$SesData->HotView->Laituri;

    /* Finish editing in Purkki. That is remove new lines from every group */
    $laituri->finishEdit();

    /* Process post call after edit if one is defined.
     * This is pre save call. */
#    $event_def = $template->getFormOption(DZE_PRE_SAVE);
    $event_def = $template->getFormEvent(DZE_PRE_SAVE);

    /* Handle the event if it was defined */
    if (soGetClass($event_def)) handleSubariEventItem($event_def, $SesData);
    if ($template->isPseudo()) {
        return dzSMH_KillView($SesData);
    } else {
            $write_result = $laituri->writeSet($SesData->BasicInfo->Lang,
                                               $template);
    }; // else if

    /* Check that commit was successful. If not notify the user */
    if ($write_result) {
        /* Add an error message to inform the user that no browse rows
           were found. */
        if (!is_array($write_result)) $write_result = array($write_result);
        foreach ($write_result as $error) {
            $SesData->ErrorLog->add($error);
        }; // foreach
        $laituri->startEdit();
        $result = DZ_STATE_GO_EDIT_LOOP;
    } else {
        /* Write ok -> call post save remote function if one defined. */
        $event_def = $template->getFormOption(DZE_POST_SAVE);

        /* Handle the event if it was defined */
        if (soGetClass($event_def) != "") handleSubariEventItem($event_def,
                                                               $SesData);
        $enter_state = $template->getViewData(DZ_VI_ENTER_STATE);
        if ($enter_state == DZ_STATE_FROM_NEW_LOOP) {
            /* Find out the following state. */
            $nextState = $template->getFormOption(DZFO_AFTER_NEW_USER);
            if ((!$nextState) &&
                (dzGetIniItem(DZIS_GENERAL,
                              DZID_FORCE_BROWSE_AFTER_NEW,
                              "app", "bool") ||
                 dzGetIniItem(DZIS_SYS,
                              DZID_FORCE_BROWSE_AFTER_NEW,
                              "dataxi", "bool"))) {
                $nextState = DZM_BROWSE;
            }; // if
            if (!$nextState) {
                $nextState = $template->getFormOption(DZFO_AFTER_NEW);
            }; // if

            if ($nextState == DZM_QUERY) {
                $result = DZ_STATE_START_QUERY;
            } else {
                $result = DZ_STATE_GO_BROWSE;

                /* Reset the last query.conditions */
                $laituri->emptyStore(LAST_QUERY);
                $laituri->insRow(-1, "", LAST_QUERY);

                /* Set the new row as the only browse row */
                $key_cols = $laituri->getBrowseKeys();
                if (!count($key_cols)) {
#echo "jee ".$laituri->__Struct."<br>";
#                    $struct = new dzStruct($laituri->__StructName);
#                    $struct->setup(str_replace(" ", "\n",
#                                   $laituri->__StructIniStr));
#                    $key_cols = $struct->getMasterKeyColNames(1);
                    $key_cols = $laituri->__Struct->getMasterKeyColNames(1);
                }; // if
                if (count($key_cols)) {
                    foreach ($key_cols as $field) {
                        $value = $laituri->getStoreItem(TISKI, $field, 0);

                        /* Set field's value as key to browse key list  */
                        $laituri->setBrowseKeyCol($field, array($value));

                        /* Put the key as a query condition */
                        $laituri->setStoreItem(LAST_QUERY, $field, 0, $value);
                    } // foreach

                    /* Set browse pointer and key counter. */
                    $laituri->__BrowseKeyCount = 1;
                    $laituri->__BrowsePos = 0;
                } else {
                    $laituri->__BrowseKeyCount = 0;
                    $laituri->__BrowsePos = -1;
                }; // else if
            } // else if ($nextState == "query")
        } else {
            $result = DZ_STATE_GO_BROWSE;
        }; // else if
    } // if write_result

    return $result;
} // dzSMH_CommitEdit


/** Handles the pseudo form data if this was a pseudo form
 *  @param dzSession $SesData Current session data
 *  @return int The next state to move to
 */
function dzSMH_CommitPseudoForm(&$SesData) {
    soDebug("dzStates: dzSMH_CommitPseudoForm", SOD_DET);
    $form_type = $SesData->HotView->Template->getViewData(DZ_VI_TYPE);
    if ($form_type == DZ_VIEW_TYPE_PSEUDO) {

        /* Process post call after read if one is defined. */
        $event_def = $SesData->HotView->Template->getFormOption(DZE_POST_PSEUDO);

        /* Handle the event if it was defined */
        if (soGetClass($event_def) != "") handleSubariEventItem($event_def,
                                                               $SesData);
        if ($SesData->HotView->Template->getFormOption(DZFO_PERSISTENT,
                                                       "bool")) {
            $result = DZ_STATE_START_QUERY;
        } else {
            $result = DZ_STATE_KILL_VIEW;
        }; // else if
    } else {
        /* Strange thing happened: we ended up here even though we do not
         * have a pseudo form to process, so try to recover. */
        $result = DZ_STATE_INIT_BROWSE;
    } // else if if pseudo

    return $result;
} // dzSMH_CommitPseudoForm


/** Deletes a row.
 *  Handles ctrl-del key event -> delete current line from the group.
 *  @param dzSession $SesData Current session data
 *  @return int The next state to move to
 */
function dzSMH_DelLine(&$SesData) {
    soDebug("dzStates: dzSMH_DelLine", SOD_DET);
    $widget = $SesData->HotView->Template->WidgetData->getItem(DZRI_WIDGET);
    $grp = soExtractVal($widget, "_", 2);
    $del_limit = $SesData->HotView->Laituri->getDeleteLimit($grp);

    /*  Check if the insert in the group is allowed. */
    if (!in_array($del_limit, array(DZGD_NONE))) {
        /* $field[0] == colname, $field[1] == rowno. */
        $field = $SesData->HotView->Template->ClientWidgetMap->getItem($widget);
        $SesData->HotView->Laituri->delGroupRow($grp, $field[1]);
    } // if

    /* Return the focus there where we left */
    $SesData->HotView->Template->addInitAction(DZIA_SET_FOCUS,
                                               $widget);
    return DZ_STATE_RECOVER_ERROR;
} // dzSMH_DelLine


/** Delete row from db.
 *  @param dzSession $SesData Current session data
 *  @return int The next state to move to
 */
function dzSMH_DelRow(&$SesData) {
    soDebug("dzStates: dzSMH_DelRow", SOD_DET);

    $delete_result = $SesData->HotView->Laituri->deleteSet();

    if ($delete_result == NULL) {
        if ($SesData->HotView->Laituri->getBrowsePos() < 0) {
            $result = DZ_STATE_START_QUERY;
        } else {
            $SesData->HotView->Laituri->copy(LAST_QUERY, TISKI);
            $result = DZ_STATE_GO_BROWSE;
        };
    } else {
        /* Add an error message to inform the user that delete failed */
        $SesData->ErrorLog->add($delete_result);
        $result = DZ_STATE_GO_BROWSE;
    } // if $delete_result

    return $result;
} // dzSMH_DelRow


/** Finishes the state machine.
 *  @param dzSession $SesData Current session data
 */
function dzSMH_Finish(&$SesData) {
    soDebug("dzStates: dzSMH_Finish", SOD_DET);

    /* Set the state where to go when next time came to state machine */
    if ($SesData->HotView->Template->RequestResult->NextState != "")
        $SesData->HotView->Template->setViewData(DZ_VI_ENTER_STATE,
                           $SesData->HotView->Template->RequestResult->NextState);

    /* Do we need to serialse the session data or
       Remove the old data from the disk. */
    switch ($SesData->HotView->Template->RequestResult->Serialize) {
        case DZMNG_SER_YES:
            soDebug("dzStates: Session serialized ", SOD_DET);
            dzManStoreSession($SesData);
            break;

        case DZMNG_SER_DEL:
            soDebug("dzStates: Session not serialized.", SOD_DET);
            dzManRemoveSessionFile($SesData->BasicInfo->Id);
            break;
    } // switch $Serialize

    /* Remove the session from the list of processed sessions */
    delFromProcessedList($SesData->BasicInfo->Id);
    soDebug("dzStates: State machine return status ".
            $SesData->HotView->Template->RequestResult->Status, SOD_DET);
} // dzSMH_Finish


/** Finish the pick up process. Picks up the searched data and
 *  set it to destination widget.
 *  @param dzSession $SesData Current session data
 *  @return int The next state to move to
 */
function dzSMH_FinishPickUp(&$SesData) {
    soDebug("dzStates: dzSMH_FinishPickUp", SOD_DET);

    /* Get tha pick up definition */
    $widget = $SesData->HotView->Template->WidgetData->getItem(DZRI_WIDGET);

    /* $field[0] == colname, $field[1] == rowno. */
    $field = $SesData->HotView->Template->ClientWidgetMap->getItem($widget);

    /* get the pick up definition for the column */
    $pick_def = $SesData->HotView->Template->getColProperty(
        $field[0], DZCPT_CONTROL, DZCP_PICK);
    $src_field = soExtractVal($pick_def, ",", 2);

    /* Get the value from the sub view and store it to active TISKI */
    $value = $SesData->HotView->Laituri->getStoreItem(CLIP, $src_field, 0);
    $SesData->HotView->Laituri->setStoreItem(TISKI, $field[0],
                                             $field[1], $value);

    /* Erase the subview data */
    $SesData->HotView->Laituri->initStore(CLIP);

    /* Set the event source so that the correct fetch field is updated */
    $SesData->FocusFieldName = $field[0];
    $SesData->FocusRow = $field[1];

    return DZ_STATE_UPD_FETCH_FIELD;
} // dzSMH_FinishPickUp


/** Handle the state when coming from client after edit or adding a new row
 *  @param dzSession $SesData Current session data
 *  @return int The next state to move to
 */
function dzSMH_FromEditLoop(&$SesData) {
    soDebug("dzStates: dzSMH_FromEditLoop", SOD_DET);
    __dzSMH_StoreClientForm($SesData);

    return DZ_STATE_HANDLE_EVENT;
} // dzSMH_FromEditLoop


/** Handle the state when coming from client after query
 *  @param dzSession $SesData Current session data
 *  @return int The next state to move to
 */
function dzSMH_FromQueryLoop(&$SesData) {
    soDebug("dzStates: dzSMH_FromQueryLoop", SOD_DET);
    __dzSMH_StoreClientForm($SesData);
    $SesData->HotView->Laituri->copy(TISKI, LAST_QUERY);

    return DZ_STATE_HANDLE_EVENT;
} // dzSMH_FromQueryLoop


/** Stores client form to hot view
 *  Common routine for few other routines.
 *  @param dzSession $SesData Current session data
 */
function __dzSMH_StoreClientForm(&$SesData) {
    /* Put the values from the form to Tiski */
    $widget_data = &$SesData->HotView->Template->WidgetData;
    $SesData->HotView->storeClientForm($widget_data);
} // __dzSMH_StoreClientForm


/** This is here for future implementations. Currently this does nothing.
 *  @param dzSession $SesData Current session data
 *  @return int The next state to move to
 */
function dzSMH_FromSubView(&$SesData) {
    soDebug("dzStates: dzSMH_FromSubView", SOD_DET);

    return DZ_STATE_HANDLE_EVENT;
} // dzSMH_FromSubView


/** Create Browse view for user
 *  @param dzSession $SesData Current session data
 *  @return int Next state
 */
function dzSMH_GoBrowse(&$SesData) {
    soDebug("dzStates: dzSMH_GoBrowse", SOD_DET);
    $template = &$SesData->HotView->Template;
    /* Get the browse mode. First take definition from View info and then from
       the form options from the source file. */
    /* Get tme maximum amount of rows in the list view */
    $list_max = $template->getFormOption(DZFO_LIST_MAX);
    $mode = $template->getViewData(DZ_VI_BROWSE_MODE);
    $bkey_count = $SesData->HotView->Laituri->getBrowseKeyCount();
    if (!$bkey_count) {
        $laituri = &$SesData->HotView->Laituri;
        $laituri->emptyStore(LAST_QUERY);
        $laituri->emptyStore(TISKI);
        $laituri->insRow(-1, "", LAST_QUERY);
        return DZ_STATE_GO_QUERY_LOOP; // <-- EXIT
    }; // if

    if (($list_max != "") &&
        ($bkey_count > intval($list_max))) {
        $mode = DZBM_FORM;
    }; // if
    $template->setViewData(DZ_VI_BROWSE_MODE, $mode);


    /* Check if the list browse button is shown */
    if (($bkey_count > $list_max) &&
        ($list_max > 0)) {
        $template->setFormOption(DZFO_ALLOW_BROWSE_LIST, 0);
    } else {
        /* Allow list mode */
        $template->setFormOption(DZFO_ALLOW_BROWSE_LIST, 1);
    } // if

    /* v-- for shorter code and readability */
    $hv = &$SesData->HotView;

    $browse_mode = $hv->Template->getViewData(DZ_VI_BROWSE_MODE);
    if ($browse_mode == DZBM_LIST) {
        $cols = $hv->Template->FormOptions->ListCols->getKeys();
        $max_list = intval(
            $hv->Template->FormOptions->ListCols->getItem(DZFO_LIST_MAX));
        $read_result = $hv->Laituri->readList($cols, $max_list);
    } else {
        $read_result = $hv->Laituri->readSet(false);
        $lock_owner = $hv->Laituri->getLockedBy();
        $hv->Template->setViewData(DZ_VI_LOCKED_BY, $lock_owner);
        $lock_info = $hv->Laituri->getLockInfo();
        $hv->Template->setViewData(DZ_VI_LOCK_INFO, $lock_info);

        /* Process post call after read if one is defined. */
        $event_def = $SesData->HotView->Template->getFormOption(DZE_POST_READ);

        /* Handle the event if it was defined */
        if (soGetClass($event_def) != "") handleSubariEventItem($event_def,
                                                               $SesData);

    } // if $browse_mode

    /* Check that the row was found */
    if ($read_result == NULL) {
        $hv->Template->setViewData(DZ_VI_MODE, DZM_BROWSE);
        if ($browse_mode != DZBM_LIST) {
                $title = " ".$hv->Laituri->getBrowsePosStr();
                $hv->Template->ScriptFeatureSpool->setAttrib(
                    DZSA_STONGA_TITLE_EXT, $title);
        } // $browse_mode
        $result = DZ_STATE_RECOVER_ERROR;
        $hv->Template->RequestResult->NextState = DZ_STATE_FROM_BROWSE;
    } else {
        $result = DZ_STATE_GO_QUERY_LOOP;
        $SesData->ErrorLog->add($read_result);
    } // if $read_result

    return $result;
} // dzSMH_GoBrowse


/** Show a dialog for user
 *  @param dzSession $SesData Current session data
 *  @return int The next state to move to
 */
function dzSMH_GODialog(&$SesData) {
    soDebug("dzStates: dzSMH_GoDialog", SOD_DET);
    /* In next state prodece the output code */
    $result = DZ_STATE_RECOVER_ERROR;
    /* When entering state machine next time go to DZ_STATE_FROM_BROWSE */
    $SesData->HotView->Template->RequestResult->NextState = DZ_STATE_FROM_SUB_VIEW;

    return $result;
} // dzSMH_GoDialog


/** Going to edit loop. Looped as long as the user commits or rollbacks the
 *  form.
 *  @param dzSession $SesData Current session data
 *  @return int The next state to move to
 */
function dzSMH_GoEditLoop(&$SesData) {
    soDebug("dzStates: dzSMH_GoEditLoop", SOD_DET);
    $enter_state = $SesData->HotView->Template->getViewData(DZ_VI_ENTER_STATE);
    if ($enter_state == DZ_STATE_FROM_NEW_LOOP) {
        $SesData->HotView->Template->setViewData(DZ_VI_MODE, DZM_NEW);
    } else {
        $SesData->HotView->Template->setViewData(DZ_VI_MODE, DZM_EDIT);
    } // if

    /* Next time we'll return in the same state as we now entered. That is
       whether FROM_EDIT_LOOP or FROM_NEW_LOOP */
    $SesData->HotView->Template->RequestResult->NextState = $enter_state;
    /* In next state prodece the output code */
    $result = DZ_STATE_RECOVER_ERROR;

    return $result;
} // dzSMH_GoEditLoop


/** Create query view for user
 *  @param dzSession $SesData Current session data
 *  @return int next state
 */
function dzSMH_GoQueryLoop(&$SesData) {
    soDebug("dzStates: dzSMH_GoQueryLoop", SOD_DET);
    $SesData->HotView->Template->setViewData(DZ_VI_MODE, DZM_QUERY);

    /* In next state prodece the output code */
    $result = DZ_STATE_RECOVER_ERROR;
    /* When entering state machine next time go to DZ_STATE_FROM_BROWSE */
    $SesData->HotView->Template->RequestResult->NextState = DZ_STATE_FROM_QUERY_LOOP;

    return $result;
} // dzSMH_GoQueryLoop


/** Sesion ID and the user name did not match. We can suspect a mean
 *  person trying to crack in.
 *  @param dzSession $SesData Current session data
 *  @return int next state
 */
function dzSMH_HackerIn(&$SesData) {
    soDebug("dzStates: dzSMH_HackerIn", SOD_DET);
    /* Hopefully the user will not send more requests */
    $SesData->HotView->Template->RequestResult->NextState = 0;
    $SesData->HotView->Template->RequestResult->Status = DZ_MANAGER_ERROR;
    $SesData->HotView->Template->RequestResult->Serialize = DZMNG_SER_NO;
    $SesData->HotView->Template->RequestResult->Screen = dzGetManagerMsg(DZ_STATE_HACKER_IN);

    return DZ_STATE_FINISH;
} // dzSMH_HackerIn


/**
 * Handles the event that occurred at the client side and decides the next state
 * @param dzSession $SesData Current session data
 * @return int The next state to move to
 */
function dzSMH_HandleEvent(&$SesData) {
    soDebug("dzStates: dzSMH_HandleEvent", SOD_DET);
    /* Handle the event that caused the return to
       the server */
    $eventHandler = new dzEvent($SesData);
    $result = $eventHandler->processEvents();

    return $result->NextState;
} // dzSMH_HandleEvent


/** Initialize browse mode
 *  @param dzSession $SesData Current session data
 *  @return int The next state to move to
 */
function dzSMH_InitBrowse(&$SesData) {
    soDebug("dzStates: dzSMH_InitBrowse", SOD_DET);

    $form_type = $SesData->HotView->Template->getViewData(DZ_VI_TYPE);
    if ($form_type != DZ_VIEW_TYPE_PICK_UP) {
        /* Set the defined browse mode. Default is DZBM_FORM */
        $mode = $SesData->HotView->Template->getFormOption(DZFO_BROWSE_MODE);
        $SesData->HotView->Template->setViewData(DZ_VI_BROWSE_MODE, $mode);
    } // if $form_type


    /* Initialize Tiski for browsing */
    $query_result = $SesData->HotView->Laituri->runQuery();

    /* Process post call after query if one is defined
      Get the call definition if one exists */
    $event_def = $SesData->HotView->Template->getFormOption(DZE_POST_QUERY);

    /* Handle the event if it was defined */
    if (soGetClass($event_def) != "") handleSubariEventItem($event_def,
                                                           $SesData);

    if ($query_result == NULL) {
        /* If no rows were found return to query */
        if ($SesData->HotView->Laituri->getBrowsePos() >= 0) {

            $result = DZ_STATE_GO_BROWSE;
        } else {
            /* Add an error message to inform the user that no browse rows
            were found. */
            $err_msg = new dzErrorMsg(DZER_NO_BROWSE_ROWS, "",
                                      DZERT_USER, DZERL_NOTIFY);
            $SesData->ErrorLog->add($err_msg);

            $result = DZ_STATE_RECOVER_ERROR;
            $SesData->HotView->Template->RequestResult->NextState = DZ_STATE_FROM_QUERY_LOOP;
        } // if $read_result
    } else  {
            /* Some error occerred during the rpc. Insert message to
               message log.  */
            $SesData->ErrorLog->add($query_result);

            $result = DZ_STATE_RECOVER_ERROR;
            $SesData->HotView->Template->RequestResult->NextState = DZ_STATE_FROM_QUERY_LOOP;
    } // if $query_result

    return $result;
} // dzSMH_InitBrowse


/** Starting state of the state machine. Store some initial values.
 *  @param dzSession $SesData Current session data
 *  @return int The next state to move to
 */
function dzSMH_Initial(&$SesData) {
    soDebug("dzStates: dzSMH_Initial", SOD_DET);

    /* Update the sessions access time if it is used */
    $upd_at = dzGetIniItem(DZIS_GENERAL, DZID_UPD_ACCESS_TIME);
    if (soGetBool($upd_at)) {
        $SesData->updateSessionAccessTime();
    } // if

    /* Store the focus place  on the form.*/
    $focus_widget = $SesData->HotView->Template->WidgetData->getItem(DZRI_WIDGET);
    $SesData->FocusGroup = intval(soExtractVal($focus_widget, "_", 2));

    /* If there is a single view get the row number */
    if (soGetClass($SesData->HotView->Template->ClientWidgetMap) == "soset") {
        /* $field[0] == colname, $field[1] == rowno. */
        $field = $SesData->HotView->Template->ClientWidgetMap->getItem($focus_widget);
    } else {
        $field = array("", "");
    }; // if

    /* If this is a dataxi form update the focus row */
    $type = $SesData->HotView->Template->getViewData(DZ_VI_TYPE);
    if ($type != DZ_VIEW_TYPE_DIALOG) {
        $SesData->HotView->Laituri->setFocusRow($SesData->FocusGroup,
                                                intval($field[1]));
    } // if
    $SesData->FocusFieldName = $field[0];
    $SesData->FocusRow = intval($field[1]);
    $SesData->FocusCol = soExtractVal($focus_widget, "_", 4);

    /* Reset the error log */
    $SesData->ErrorLog = new dzError();

    /* Reset the request result information */
    $SesData->HotView->Template->resetReqResult();

    /* Next go to state that deals with current form mode */
    $result = $SesData->HotView->Template->getViewData(DZ_VI_ENTER_STATE);

    /* Check if the session was suspended. If was check the given password.
       If password matches set the session open. Otherwise stay suspended. */
    if ($SesData->Suspend) {
        soDebug("dzStates: Session is suspended -> check the password.",
                SOD_LO);
        $SesData->HotView->storeClientForm(
                $SesData->HotView->Template->WidgetData);
        $passwd =  $SesData->HotView->Laituri->getStoreItem(TISKI,
                                                DZ_PASSWD_STORE_ITEM, 0);
        $user_check_result = $SesData->HotView->Laituri->VerifyUser(
                                            $SesData->BasicInfo->UserID,
                                            $passwd);
        if ($user_check_result) {
            soDebug("dzStates: Password ok -> unlock session.", SOD_LO);
            $SesData->Suspend = false;
        } else {
            soDebug("dzStates: Password did not match -> stay suspended.",
                    SOD_LO);
            $err_msg = new dzErrorMsg(DZER_PASSWORD_MISMATCH, "",
                                    DZERT_USER, DZERL_NOTIFY);
            $SesData->ErrorLog->add($err_msg);
            $SesData->HotView->Laituri->setStoreItem(TISKI,
                                        DZ_PASSWD_STORE_ITEM, 0, "");
            $result = DZ_STATE_RECOVER_ERROR;
        } // if
    } // if

    return $result;
} // dzSMH_Initial


/** Create the initial view
 *  @param dzSession $SesData Current session data
 *  @return string Html code that is sent to client
 */
function dzSMH_InitialView(&$SesData) {
    soDebug("dzStates: dzSMH_InitialView", SOD_DET);
    /* Reset the current view */
    $SesData->ViewPos = -1;

    /* Create an informative view. Welcome view. */

    /* XXX Dialog source files must be set to consts. And the type may change  */
    $welcomeView = new dzView($SesData->BasicInfo,
                              "welcome.html",
                              DZ_VIEW_TYPE_DIALOG);
    $type = DZT_TYPE_HTML;

    $welcomeFeats = "event_wrapper exit_event";
    $welcomeView->Template->ScriptFeatureSpool->addGenFeatures($welcomeFeats);

    /* Create the output filter according to the specified output type */
    switch ($type) {
        case DZT_TYPE_HTML:
            soDebug("dzStates: Created Html output filter for welcome view ",
                     SOD_DET);
            include_once("dzouthtml.php");
            /* OK! The third parameter is grab in the next line. Too bad. dzAsm
               requires a reference parameter here thus we cannot pass NULL.
               Actually third parameter is type of dzLaituri. But in this case
               it is not needed. So let's give a soSet object to dzAsm So it
               would be happy. We are anyway. Jihuu! */
            $out_filter = new dzAsm($welcomeView->Template,
                                       $SesData->LastAccess, new soSet());
            break;
    } //switch $source_type

    $form = $out_filter->getFormCode($SesData->ErrorLog);
    $SesData->HotView = $welcomeView;

    /* Set finishing parameters */
    $SesData->HotView->Template->RequestResult->NextState = DZ_STATE_FROM_INITIAL;
    $SesData->HotView->Template->RequestResult->Screen = $form;

    return DZ_STATE_FINISH;
} // dzSMH_InitialView


/** Handle ctrl-insert key event -> insert a new line at the curren line in
 *  the current group.
 *  @param dzSession $SesData Current session data
 *  @return int The next state to move to
 */
function dzSMH_InsertLine(&$SesData) {
    soDebug("dzStates: dzSMH_InsertLine", SOD_DET);
    $widget = $SesData->HotView->Template->WidgetData->getItem(DZRI_WIDGET);
    $grp = soExtractVal($widget, "_", 2);
    $ins_limit = $SesData->HotView->Laituri->getInsertLimit($grp);

    /*  Check if the insert in the group is allowed. */
    if (!in_array($ins_limit, array(DZGI_ONE_END, DZGI_ANY_END, DZGI_NONE))) {
        /* $field[0] == colname, $field[1] == rowno. */
        $field = $SesData->HotView->Template->ClientWidgetMap->getItem($widget);
        $SesData->HotView->Laituri->cancelNew($grp, $field[1]);
        $SesData->setDefaultValues($grp, $field[1]);
    } // if

    /* Return the focus there where we left */
    $SesData->HotView->Template->addInitAction(DZIA_SET_FOCUS, $widget);

    return DZ_STATE_RECOVER_ERROR;
} // dzSMH_InsertLine


/** Inserts new sub-form into view
 *  @param dzSession $SesData Current session data
 *  @return int The next state to move to
 */
function dzSMH_InsertForm(&$SesData) {
    soDebug("dzStates: dzSMH_InsertForm", SOD_DET);
    /* The view data should be stored in session's Context property */
    $SesData->HotView = $SesData->ViewStack->pushView($SesData->HotView,
                                                      $SesData->Context);
    if ($SesData->HotView->Error) {
        $err_msg = new dzErrorMsg(DZER_SRC_PARSE_FAILED, "",
                                  DZERT_SOURCE, DZERL_ERROR);
        $SesData->ErrorLog->add($err_msg);
        return DZ_STATE_KILL_VIEW;  // <-- EXIT!!!
    } // if

    /* If the pre call is defined , call the defined function.
       First construct the property name. That is: mode_name+'_enter_call'
       For pseudo forms it is just 'enter_call'  */
    $mode = $SesData->HotView->Template->getViewData(DZ_VI_MODE);

    /* Get the call definition if one exists */
    $pre_call_def =
        $SesData->HotView->Template->getFormOption(DZE_PRE_FORM.$mode);
    if ($pre_call_def == NULL) {
        $pre_call_def =
        $SesData->HotView->Template->getFormOption(DZE_PRE_FORM);
    }; // if

    /* Handle the event if it was defined */
    if (soGetClass($pre_call_def) == "soset") {
        handleSubariEventItem($pre_call_def, $SesData);
    }; // if

    switch ($SesData->Context->Type) {
        case DZ_VIEW_TYPE_DIALOG:
            $SesData->HotView->Template->setViewData(DZ_VI_SOURCE_TYPE,
                                                     DZT_TYPE_HTML);
            $result = DZ_STATE_GO_DIALOG;
            break;

        case DZ_VIEW_TYPE_DATAXI:
            if ($SesData->HotView->Template->isPseudo()) {
                $result = DZ_STATE_START_NEW;
            } else {
                $result = DZ_STATE_START_QUERY;
            }; // if
            break;

        case DZ_VIEW_TYPE_PSEUDO:
            $result = DZ_STATE_START_QUERY;
            break;

        case DZ_VIEW_TYPE_PICK_UP:
            /* get the pick up definition for the column */
            $pick_def = $SesData->HotView->Template->getColProperty(
                $field[0], DZCPT_CONTROL, DZCP_PICK);
            /* Set the browse mode. That is either list view or query. */
            $mode = soExtractVal($pick_def, ",", 3);
            if ($mode == "query") {
                /* Start with querying */
                $result = DZ_STATE_START_QUERY;
            } else {
                /* Show list view right away. (Default) */
                $SesData->HotView->Template->setViewData(DZ_VI_BROWSE_MODE,
                                                         DZBM_LIST);
                $result = DZ_STATE_INIT_BROWSE;
             } // if $mode
            break;

        default:
            $result = DZ_STATE_START_QUERY;
    } // switch

    return $result;
} // dzSMH_InsertForm


/** Jump to some browse position. This is after the user has choosen the row
 *  from the list view.
 *  @param dzSession $SesData Current session data
 *  @return int The next state to move to
 */
function dzSMH_jumptobrowsepos(&$SesData) {
    soDebug("dzStates: dzSMH_jumptobrowsepos", SOD_DET);

    $pos = intval($SesData->HotView->Template->WidgetData->getItem(DZRI_OPTIONS));
    $SesData->HotView->Laituri->moveBrowsePos($pos);

    if ($SesData->HotView->Template->getViewData(DZ_VI_TYPE) !=
        DZ_VIEW_TYPE_PICK_UP) {
        $SesData->HotView->Template->setViewData(DZ_VI_BROWSE_MODE, DZBM_FORM);
        $result = DZ_STATE_GO_BROWSE;
    } else {
        soDebug("dzStates: Update TISKI and finish pick up", SOD_DET);
        $result = DZ_STATE_TO_PARENT_VIEW;
        /* Update TISKI. */
        $read_result = $SesData->HotView->Laituri->readSet(false);
        if ($read_result != NULL) {
            $result = DZ_STATE_GO_BROWSE;
            $SesData->ErrorLog->add($read_result);
        } // if $read_result

    } // if

    return $result;
} // dzSMH_jumptobrowsepos


/** Kills the current view
 *  @param dzSession $SesData Current session data
 *  @return int The next state to move to
 */
function dzSMH_KillView(&$SesData) {
    /* Check are we returning from pick up */
    $type = $SesData->HotView->Template->getViewData(DZ_VI_TYPE);
    if ($type == DZ_VIEW_TYPE_PICK_UP) {
        soDebug("dzStates: dzSMH_KillView/subview", SOD_DET);
        /* Yes pick up sub view was cancelled. Return to the parent view */
        $SesData->HotView = $SesData->ViewStack->popView();
        $result = DZ_STATE_ACTIVATE_VIEW;
        return $result;         // <--- EXIT!!
    } // if $SesData...

    /* Check if this was a sub view. If yes, just dispose it.
       Otherwise kill view and return to next view in the view stack
       if there is any.  */
    if ($SesData->ViewStack->getViewCount() > 1) {
        /* If type is pseudo form preserve init actions */
        if ($type == DZ_VIEW_TYPE_PSEUDO){
            $sf_spool = &$SesData->HotView->Template->ScriptFeatureSpool;
            $init_set = $sf_spool->getAttrib(DZSA_INIT_ACTION);
            $SesData->HotView = $SesData->ViewStack->popView();
            $SesData->HotView->Template->ScriptFeatureSpool->setAttrib(
                DZSA_INIT_ACTION, $init_set);
        } else {
            $SesData->HotView = $SesData->ViewStack->popView();
        } //$type
        $result = DZ_STATE_RECOVER_ERROR;
        soDebug("dzStates: dzSMH_KillView/pseudo", SOD_DET);
        return $result;          // <--- EXIT!!
    } else {
        $delId = $SesData->ViewOrder->getItem($SesData->ViewPos);
        soDebug("dzStates: dzSMH_KillView/Id=$delId, ".
                "ViewPos=".$SesData->ViewPos, SOD_DET);
        /* If we were eding release locks too */
        $enter_state = $SesData->HotView->Template->getViewData(
                                                DZ_VI_ENTER_STATE);
        if ($enter_state == DZ_STATE_FROM_EDIT_LOOP) {
            $release_result = $SesData->HotView->Laituri->releaseLock();
            if ($release_result != NULL) {
                /* Some error occerred during the rpc. Insert message to
                message log.  */
                $SesData->ErrorLog->add($release_result);
            } // if
        } // if $enter_state
        $SesData->deleteViewStack($delId);
    } // $SesData->ViewStack->getViewCount()

    /* Do we still have views? */
    if ($SesData->ViewOrder->count() == 0) {
        /* No more views. Go to initial state */
        $SesData->ViewPos = -1;
        $result = DZ_STATE_GO_INITIAL;
    } else {
        /* The view is unserialised in the next state */
        $SesData->ViewPos = 0;
        $result = DZ_STATE_ACTIVATE_VIEW;
    }
    return $result;
} // dzSMH_KillView


/** Delete row from db.
 *  @param dzSession $SesData Current session data
 *  @return int The next state to move to
 */
function dzSMH_RecoverError(&$SesData) {
    soDebug("dzStates: dzSMH_RecoverError", SOD_DET);

    return DZ_STATE_PRODUCE_OUTPUT;
} // dzSMH_RecoverError


/** Return to query after browse. When this current view is pick
 *  return direct to main form-
 *  @param dzSession $SesData Current session data
 *  @return int The next state to move to
 */
function dzSMH_ReturnQuerying(&$SesData) {
    soDebug("dzStates: dzSMH_ReturnQuerying", SOD_DET);
    $type = $SesData->HotView->Template->getViewData(DZ_VI_TYPE);

    if ($type == DZ_VIEW_TYPE_PICK_UP) {
        $widget = $SesData->HotView->Template->WidgetData->getItem(DZRI_WIDGET);
        $SesData->HotView->Template->addInitAction(DZIA_SET_FOCUS, $widget);
        $result = DZ_STATE_KILL_VIEW;
    } else {
        $result = DZ_STATE_START_QUERY;
    } // if

    return $result;
} // dzSMH_ReturnQuerying


/** Show help screen for the user.
 *  This is single form related.
 *  @param dzSession $SesData Current session data
 *  @return string The html source for the query
 */
function dzSMH_ShowHelp(&$SesData) {
    soDebug("dzStates: dzSMH_ShowHelp", SOD_DET);
    $helpFile = $SesData->HotView->Template->getFormOption(DZFO_HELP);
    $view_data = new dzViewData(DZ_VIEW_TYPE_DIALOG, true, $helpFile, false);
    /* Save the view data for the next state where the new form will be created */
    $SesData->Context = $view_data;

   return DZ_STATE_INSERT_FORM;
} // dzSMH_ShowHelp


/** Create Edit view for user
 *  @param dzSession $SesData Current session data
 *  @return boolean True(1) if locked and ready to edit or false(0) if
 *      locking failed
 */
function dzSMH_StartEdit(&$SesData) {
    soDebug("dzStates: dzSMH_StartEdit", SOD_DET);

    /* lock, refresh and build */
    $rpc_result = $SesData->HotView->Laituri->readSet(true);
    /* If no error messages proceed */
    if ($rpc_result == NULL) {

        /* Prepare Purkki for editing */
        $SesData->HotView->Laituri->startEdit();
        $SesData->setDefaultValues();

        /* We must fool the state machine a bit here. We pretend that
           that we came in with DZ_STATE_FROM_EDIT_LOOP state. This is made
           to produce correct view later in DZ_STATE_GO_EDIT_LOOP state. */
        $SesData->HotView->Template->setViewData(DZ_VI_ENTER_STATE,
                                                 DZ_STATE_FROM_EDIT_LOOP);
        $result = 1;
    } else {
        $SesData->ErrorLog->add($rpc_result);
        $result = 0;
    };

    return $result;
} // dzSMH_StartEdit


/** Start the pick up process. Create sub view in query mode
 *  after that view will proceed to browse and finally return
 *  back to the parent view.
 *  @param dzSession $SesData Current session data
 *  @return int The next state to move to
 */
function dzSMH_StartPickUp(&$SesData) {
    soDebug("dzStates: dzSMH_StartPickUp", SOD_DET);

    $widget = $SesData->HotView->Template->WidgetData->getItem(DZRI_WIDGET);
    /* $field[0] == colname, $field[1] == rowno. */
    $field = $SesData->HotView->Template->ClientWidgetMap->getItem($widget);

    /* get the pick up definition for the column */
    $pick_def = $SesData->HotView->Template->getColProperty(
        $field[0], DZCPT_CONTROL, DZCP_PICK);

    if (!$pick_def) {
        $result = DZ_STATE_RECOVER_ERROR;
    } else {
        soDebug("dzStates: Found pick up definition: ".$pick_def, SOD_DET);

        list($pick_type, $pick_type_def) = soExplode($pick_def, "://");

        /* Handle different pick types */
        switch ($pick_type) {
            case DZMT_SYS_FORM:
            case DZMT_NALLE_FORM:
                if ($pick_type == DZMT_SYS_FORM) {
                    /* IMPORTANT !!!!
                     * Sysform picks should have a user level check !!! */
                    $sys_folder = dzGetDataxiPath();
                    $path = $sys_folder."/".DZIS_DIALOGS;
                } else {
                    $path = dzGetIniPath(DZID_FORM_SOURCE_FOLDER);
                };
                $form_src = soExtractVal($pick_type_def, ",", 1);
                $form_src = "file://".$path."/".$form_src;

                /* Insert new view (pick up view) to view stack */
                $view_data = new dzViewData(DZ_VIEW_TYPE_PICK_UP, true,
                                            $form_src, false);
                /* Save the view data for the next state where
                   the new form will be created */
                $SesData->Context = $view_data;
                $result = DZ_STATE_INSERT_FORM;
                break;

            default:
                $result = DZ_STATE_RECOVER_ERROR;
        } // switch

    } // if $pick_Def


    return $result;
} // dzSMH_StartPickUp


/** Initialize the querying of the data
 *  @param dzSession $SesData Current session data
 *  @return string The html source for the query
 */
function dzSMH_StartQuery(&$SesData) {
    $cache = &$SesData->HotView->Template->getCache();
    $SesData->HotView->Laituri->setupGroups($cache->Groups,
        array(TISKI, TAFFEL));
    /* Add one row to each column. */
    $SesData->HotView->Laituri->insRow();

    $view_type = $SesData->HotView->Template->getViewData(DZ_VI_TYPE);
#    if ($view_type == DZ_VIEW_TYPE_PSEUDO) {
        $SesData->setDefaultValues(-1, -1, 1);
#    } // if

    return DZ_STATE_GO_QUERY_LOOP;
} // dzSMH_StartQuery


/** Initialize the insertion of a new data
 *  @param dzSession $SesData Current session data
 *  @return string The html source for the query
 */
function dzSMH_StartNew(&$SesData) {
    soDebug("dzStates: dzSMH_StartNew", SOD_DET);
    $SesData->HotView->Laituri->emptyStore(TISKI);

    /* Initialize Purkki for editing */
    $SesData->HotView->Laituri->startEdit();
    $SesData->setDefaultValues();

    $pre_call_def =
        $SesData->HotView->Template->getFormOption(DZE_PRE_FORM.$mode);
    if ($pre_call_def == NULL) {
        $pre_call_def =
            $SesData->HotView->Template->getFormOption(DZE_PRE_FORM);
    }; // if

    /* Handle the pre-form event if it was defined */
    if (soGetClass($pre_call_def) == "soset") {
        handleSubariEventItem($pre_call_def, $SesData);
    }; // if

    /* Store the state where to return after new view
       if we were browsing will return to browse */
    $enter_state = $SesData->HotView->Template->getViewData(DZ_VI_ENTER_STATE);
    if ($enter_state == DZ_STATE_FROM_QUERY_LOOP) {
        $followingState = "query";
    } else {
        $followingState = "browse";
    } // if
    $SesData->HotView->Template->setFormOption(DZFO_AFTER_NEW,
                                               $followingState);

    /* We must fool the state machine a bit here. We pretend that
       that we came in with DZ_STATE_FROM_NEW_LOOP state. This is made
       to produce correct view later in DZ_STATE_GO_EDIT_LOOP state. */
    $SesData->HotView->Template->setViewData(DZ_VI_ENTER_STATE,
                                             DZ_STATE_FROM_NEW_LOOP);

    return DZ_STATE_GO_EDIT_LOOP;
} // dzSMH_StartNew


/** Set the session as suspended
 *  @param dzSession $SesData Current session data
 *  @return string The final view and scripts to send to client
 */
function dzSMH_Suspend(&$SesData) {
    soDebug("dzStates: dzSMH_Suspend", SOD_DET);
    /* Get the source stream for the suspend prompt */
    $path = dzGetDataxiPath()."/".DZIS_DIALOGS;
    $src_stream = "file://".$path."/".DZ_SUSPEND_PROMPT;
    $view_data = new dzViewData(DZ_VIEW_TYPE_PSEUDO,
                               false, $src_stream);
    /* Save the view data for the next state where
       the new form will be created */
    $SesData->Context = $view_data;

    /* Mark the session suspended */
    $SesData->Suspend = true;

    return DZ_STATE_INSERT_FORM;
} // dzSMH_Suspend


/** Remove the views and session data from the database.
 *  @param dzSession $SesData Current session data
 *  @return string The final view and scripts to send to client
 */
function dzSMH_TerminateSes(&$SesData) {
    soDebug("dzStates: dzSMH_TerminateSes", SOD_DET);

    /* Remove session from the session base. Send close_session
       request to Kone */
    $itu = new dzItu();
    /* set request type */
    $itu->setBlockItem(DZI_CONTROL, DZK_REQUEST, DZK_REQ_CLOSE_SES);
    /* Set user information */
    $itu->setBlockItem(DZI_CONTROL, DZK_USER, $SesData->BasicInfo->UserID);
    $itu->setBlockItem(DZI_CONTROL, DZK_SESSION, $SesData->BasicInfo->Id);
    /* Send result to Itu */
    $result_itu = sendRpcToKone($itu);
    /* check for rpc error */
    if (isRpcError($result_itu)) {
        $fault_string = getRpcErrorText($result_itu);
        soDebug("dzStates: Session id remove failed. Rpc error: $fault_string", SOD_HI_E);
    } // if (isRpcError($result_itu))

    /* Delete views from the disk */
    $icount = $SesData->ViewOrder->count();
    for ($c = 0; $c < $icount; $c++) {
        $SesData->removeViewStackFile($SesData->ViewOrder->getItem($c));
    }

    /* Remove the session from the system file.*/
    delSessionFromFile($SesData->BasicInfo->Id);

    /* Just put some dialog to show. It is not shown anyway
       before the browser is closed. */
    $finish_view = new dzView($SesData->BasicInfo, "end.html",
                              DZ_VIEW_TYPE_DIALOG);
    $type = DZT_TYPE_HTML;

    /* Find out if a new window was opened. If yes close it. */
    $open_new_window = soGetBoolValue(dzGetIniItem(DZIS_GENERAL,
                                                   DZID_OPEN_WINDOW));
    if ($open_new_window) {
        $view_feats = "end_session_window_close";
    } else {
        $view_feats = "end_session";
    } // if
        $finish_view->Template->ScriptFeatureSpool->addGenFeatures($view_feats);


    /* Create the output filter according to the specified output type */
    switch ($type) {
        case DZT_TYPE_HTML:
            soDebug("dzStates: Created Html output filter for finished view ", SOD_DET);
            include_once("dzouthtml.php");
            /* OK! The third parameter is grab in the next line. Too bad. dzAsm
               requires a reference parameter here thus we cannot pass NULL.
               Actually third parameter is type of dzLaituri. But in this case
               it is not needed. So let's give a soSet object to dzAsm So it
               would be happy. We are anyway. Jihuu! */
            $out_filter = new dzAsm($finish_view->Template,
                                    $SesData->LastAcsess, new soSet());
            break;
    } //switch $source_type

    $form = $out_filter->getFormCode(array(), $SesData->ErrorLog);
    $SesData->HotView = $finish_view;

    /* Set finishing parameters */
    $SesData->HotView->Template->RequestResult->NextState = 0;
    $SesData->HotView->Template->RequestResult->Screen = $form;
    $SesData->HotView->Template->RequestResult->Status = DZ_MANAGER_END;
    $SesData->HotView->Template->RequestResult->Serialize = DZMNG_SER_DEL;

    return DZ_STATE_FINISH;
} // dzSMH_TerminateSes


/** Pop the next view from the view stack and set the results from the
 *  subview.
 *  @param dzSession $SesData Current session data
 *  @return int The next state to move to
 */
function dzSMH_ToParentView(&$SesData) {
    soDebug("dzStates: dzSMH_ToParentView", SOD_DET);

    /* Get the subview type */
    $subview_type = $SesData->HotView->Template->getViewData(DZ_VI_TYPE);

    /* If sub view was data form. Save the form data */
    if (soGetClass($SesData->HotView->Laituri) == "dzlaituri") {
        /* Get the data from the subview form */
        $store = $SesData->HotView->Laituri->getStore(TISKI);
    } // if

    /* Pop the next view from the view stack and set it active view */
    $SesData->HotView = $SesData->ViewStack->popView();

    /* If sub view was data form. Save the form data */
    if (soGetClass($SesData->HotView->Laituri) == "dzlaituri") {
        /* Store the data from the sub view. */
        $SesData->HotView->Laituri->setStore(CLIP, $store);
    } // if

    switch ($subview_type) {
        case DZ_VIEW_TYPE_PICK_UP:
            $result = DZ_STATE_FINISH_PICK_UP;
            break;

        default:
            $result = DZ_STATE_RECOVER_ERROR;
    } // switch

    return $result;
} // dzSMH_ToParentView


/** Remove the views and session data from the database.
 *  @param dzSession $$SesData Current session data
 *  @return int The next state
 */
function dzSMH_UndefinedState(&$SesData) {
    soDebug("dzStates: dzSMH_UndefinedState", SOD_DET);
    dzSysError("The State machine reached an undefined state", DZSE_SYSTEM);

    return DZ_STATE_GO_INITIAL;
} // dzSMH_UndefinedState


/** Update a fetch field
 *  @param dzSession $SesData Current session data
 *  @return int The next state
 */
function dzSMH_UpdFetchField(&$SesData) {
    $mode = $SesData->HotView->Template->getViewData(DZ_VI_MODE);
    if ($mode == DZM_QUERY) {
        soDebug("dzStates: dzSMH_UpdFetchField skipped for query mode",
                SOD_DET);
        return DZ_STATE_VALIDATE_FIELD;
    }; // if

    soDebug("dzStates: dzSMH_UpdFetchField", SOD_DET);
    $fetch_data_arr = $SesData->HotView->Template->getFetchingArray(
                                        $SesData->FocusFieldName);

    /* Update all fetch target fields */
    foreach ($fetch_data_arr as $col_data) {
        $where_data = $SesData->HotView->Laituri->getFetchWhereValues(
                                                      $col_data->WhereData,
                                                      $SesData->FocusRow);
        /* Fetch is either done by kone or through @eval() */
        $result_set = NULL;
        $split = soSplitStr($col_data->SourceTable, "://", 1);
        if (!count($split)) $split = array("", "");

        if ($split[0] == "eval") {
            /* fetch=eval://file_to_include:function_name:table_name */
            $split = soExplode($split[1], ":");
            $split[0] = str_replace("~", dzGetMainScriptPath(), $split[0]);
            $params = array("wheredata" => $where_data,
                            "wherecols" => $col_data->WhereCols,
                            "fetchcols" => $col_data->FetchCols,
                            "targetcol" => $col_data->TargetCol,
                            "sourcetable" => $split[2],
                            "joinstr" => $col_data->JoinStr
                            );
            eval("include_once(\"".$split[0]."\"); ".
                 "\$result_set = ".$split[1]."(\$params);");
            if ((gettype($result_set) == "object") &&
                (soGetClass($result_set) == "soarrayset")) {
                $fetch_result = NULL;
            } else {
                $fetch_result = new dzErrorMsg(DZER_FETCH_FAILED, "eval",
                                               DZERT_SYSTEM, DZERL_ERROR);
            }; // else if
        } else {
            $fetch_result = $SesData->HotView->Laituri->fetch(
                $col_data->SourceTable,
                $col_data->WhereCols,
                $where_data,
                $col_data->FetchCols,
                $col_data->JoinStr,
                $result_set);
        }; // else if

        if ($fetch_result) {
            /* Some error occerred during the rpc. Insert message to
             * message log.  */
            $SesData->ErrorLog->add($fetch_result);
            /* An error occurred skip the rest */
            break;
        } else {
            /* fetch request ok.
             * Set the fetched value to the field */
            $value = "";
            foreach ($col_data->FetchCols as $key) {
                $tmp_key = soExtractVal($key, ":", 1)."#";
                $value = soJoinStr($value, $col_data->JoinStr,
                    $result_set->getArrayItem($tmp_key, 0), 1);
            }; // foreach
            $SesData->HotView->Laituri->setStoreItem(TISKI,
                                                    $col_data->TargetCol,
                                                    $SesData->FocusRow,
                                                    $value);
        } // if

    } // foreach;

    return DZ_STATE_VALIDATE_FIELD;
} // dzSMH_UpdFetchField


/** Check fields validy.
 *  @param dzSession $SesData Current session data
 *  @return int The next state
 */
function dzSMH_ValidateField(&$SesData) {
    soDebug("dzStates: dzSMH_ValidateField", SOD_DET);
    $laituri = &$SesData->HotView->Laituri;
    $template = &$SesData->HotView->Template;
    $widget = $template->WidgetData->getItem(DZRI_WIDGET);

    /* $field[0] == colname, $field[1] == rowno. */
    $field = $template->ClientWidgetMap->getItem($widget);

    $validate_def = $template->getColProperty(
        $field[0], DZCPT_CONTROL, DZCP_VALIDATE);

    $type = soExtractVal($validate_def, "://", 1);
    /* If negation used remove the exlamation mark */
    if ($type[0] == '!') {
        $type = soSubStr($type, 1, strlen($type)-1);
        $negation = true;
    } else {
        $negation = false;
    }// if $type

    /* If the field is not empty */
    if ($laituri->getStoreItem(TISKI, $field[0], $field[1]) != "")
        switch ($type) {
            case "table":
                $table_def = soExtractVal($validate_def, "://", 2);
                $db_table = soExtractVal($table_def, ".", 1);
                $col_defs = soExtractVal($table_def, ".", 2);

                $keys = $template->getFetchRequestKeys($col_defs, "key");
                $where_data = $template->getFetchRequestKeys($col_defs, "val");

                /* Add the current field */
                $where_data[] = SO_DOLLAR.$field[0];
                $vals = $laituri->getFetchWhereValues($where_data, $field[1]);

                $check_result = $laituri->fetch($db_table, $keys, $vals);
                if (soGetClass($check_result) == "soarrayset") {
                    $key = $keys[count($keys)-1]."#";
                    $fetch_result =
                        $check_result->getItem(soExtractVal($key, ":", 1));

                    $fetch_result = (soGetBool($fetch_result[0] != "") xor
                                     soGetBool($negation));

                    if ($fetch_result) {
                        /* Validate ok, set focus to next component. Acts
                        *  like the tab key was pressed  */
                        $template->addInitAction(DZIA_TO_NEXT_COMPONENT,
                                                 $widget);
                    } else {
                        $template->addInitAction(DZIA_SET_FOCUS, $widget);
                        /* Validate failed */
                        $err_msg = new dzErrorMsg(DZER_TABLE_VALIDATE_FAILED,
                                                  "", DZERT_USER,
                                                  DZERL_NOTIFY);
                        $SesData->ErrorLog->add($err_msg);
                        /* Return the focus there where we left and set the
                         * current field as an error field*/
                        $template->addInitAction(DZIA_SET_ERROR_FLAG,
                                                 $widget);
                    } // if $key
                } else {
                    $SesData->ErrorLog->add($check_result);
                }; // else if
                break;

            default:
                $template->addInitAction(DZIA_SET_FOCUS,
                                                        $widget);
        }; // switch

    return DZ_STATE_RECOVER_ERROR;
} // dzSMH_ValidateField

?>
